package com.neusoft.neuiotms.dcam.fixed.controller;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.auth.dto.AuthUserDTO;
import com.neusoft.bizcore.auth.model.AuthOganization;
import com.neusoft.bizcore.auth.repository.AuthOganizationRepository;
import com.neusoft.bizcore.auth.service.AuthUserService;
import com.neusoft.bizcore.web.bean.TreeBean;
import com.neusoft.bizcore.web.dto.result.PageResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.neuiotms.common.constant.AHConstants;
import com.neusoft.neuiotms.dcam.common.service.LocationService;
import com.neusoft.neuiotms.dcam.fixed.dto.AuthOrgUserDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryDutyDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryDutyHistoryDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryResultDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryDutyStatus;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryDutyHistoryService;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryDutyService;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryResultService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Api(tags = "盘点任务管理")
@RestController
@RequestMapping(value = "/api/w/fixed/inventory/dutys")
public class InventoryDutyController {

    @Autowired
    private InventoryDutyService inventoryDutyService;
    @Autowired
    private InventoryResultService inventoryResultService;
    @Autowired
    private AuthOganizationRepository authOganizationRepository;
    @Autowired
    private AuthUserService authUserService;
    @Autowired
    private LocationService locationService;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private InventoryDutyHistoryService inventoryDutyHistoryService;

    @ApiOperation("查询所有盘点任务")
    @GetMapping
    public ResultListDTO<InventoryDutyDTO> index(final Searchable searchable) {
        final List<InventoryDutyDTO> DTOs = this.inventoryDutyService.findAll(searchable);
        final ResultListDTO<InventoryDutyDTO> result = ResultListDTO.success(DTOs);
        return result;
    }

    @ApiOperation("查询当前用户所有盘点任务")
    @GetMapping("/me")
    public ResultListDTO<InventoryDutyDTO> indexMe(final Searchable searchable, final UserBean userBean) {
        searchable.put("account", userBean.getUsername());
        if (!searchable.hasKey("notstatus")) {
            searchable.put("status", InventoryDutyStatus.doing);
        }
        //        searchable.put("notstatus", InventoryDutyStatus.created);
        final List<InventoryDutyDTO> DTOs = this.inventoryDutyService.findAll(searchable);
        final ResultListDTO<InventoryDutyDTO> result = ResultListDTO.success(DTOs);
        return result;
    }

    @ApiOperation("分页查询所有盘点任务")
    @GetMapping("/p")
    public PageResultDTO<InventoryDutyDTO> search(final Pageable pageable, final Searchable searchable) {
        return PageResultDTO.success(this.inventoryDutyService.search(pageable, searchable));
    }

    @ApiOperation("分页查询当前用户所有盘点任务")
    @GetMapping("/me/p")
    public PageResultDTO<InventoryDutyDTO> searchMe(final Pageable pageable, final Searchable searchable,
            final UserBean userBean) {
        searchable.put("account", userBean.getUsername());
        searchable.put("notstatus", InventoryDutyStatus.created);
        return PageResultDTO.success(this.inventoryDutyService.search(pageable, searchable));
    }

    /**
     * 下载离线盘点任务文件
     *
     * @param response
     * @param userBean
     */
    @GetMapping(value = "/download/me")
    public void downloadPan(final HttpServletResponse response, final UserBean userBean) {

        final List<Asset> allAssetList = this.assetRepository.findAll();
        final Map<String, Asset> assetMap = Maps.newHashMap();
        allAssetList.stream().forEach(it -> {
            assetMap.put(it.getCode(), it);
        });

        final Searchable searchable = new Searchable();
        searchable.put("account", userBean.getUsername());
        searchable.put("status", InventoryDutyStatus.doing);
        // 所有的任务
        final List<InventoryDutyDTO> data = this.inventoryDutyService.findAll(searchable);

        data.forEach(duty -> {
            final Searchable s = new Searchable();
            s.put("dutyId", duty.getId());
            final List<InventoryResultDTO> results = this.inventoryResultService.findAll(s);

            results.forEach(d -> {
                //                final Asset asset = this.assetRepository.findByCode(d.getCode());
                final Asset mAsset = assetMap.get(d.getCode());
                if (null != mAsset) {
                    d.setComputerRoom(mAsset.getComputerRoom());
                    d.setCabinet(mAsset.getCabinet());
                }
            });
            duty.setDutyResults(results);
        });

        // 可用用户
        final List<AuthOrgUserDTO> availableUsers = Lists.newArrayList();
        if (userBean.getOrgs().size() > 0) {
            final String orgCode = userBean.getOrgs().get(0);
            final List<AuthOganization> list = this.authOganizationRepository.findAll();
            // 科技公司部门的code都是以kj开头
            if (orgCode.indexOf(AHConstants.BELONG_KJ_CODE) > -1) {
                final List<AuthOganization> availableOrgModels =
                        list.stream().filter(it -> it.getCode().indexOf(AHConstants.BELONG_KJ_CODE) > -1)
                                .collect(Collectors.toList());

                availableUsers
                        .addAll(availableOrgModels.stream().map(it -> this.convert(it)).collect(Collectors.toList()));

            } else {
                final List<AuthOganization> availableOrgModels =
                        list.stream().filter(it -> "root".equals(it.getCode())
                                || "root".equals(it.getParent().getCode()))
                                .collect(Collectors.toList());
                availableUsers
                        .addAll(availableOrgModels.stream().map(it -> this.convert(it)).collect(Collectors.toList()));
            }
        }

        availableUsers.forEach(it -> {
            final Searchable search = new Searchable();
            search.put("orgCode", it.getCode());
            final List<AuthUserDTO> users = this.authUserService.findAll(search);
            it.getUsers().addAll(users.stream().map(user -> this.convert(user)).collect(Collectors.toList()));
        });

        final List<Map<String, String>> availableLocations = Lists.newArrayList();
        if (userBean.getOrgs().size() > 0) {
            final String orgCode = userBean.getOrgs().get(0);
            // 科技公司部门的code都是以kj开头
            if (orgCode.indexOf(AHConstants.BELONG_KJ_CODE) > -1) {
                final List<TreeBean> locTree = this.locationService.tree(AHConstants.BELONG_KJ_CODE);
                this.flatLocTree(availableLocations, locTree);
            } else {
                final List<TreeBean> locTree = this.locationService.tree(AHConstants.BELONG_SL_CODE);
                this.flatLocTree(availableLocations, locTree);
            }
        }

        final Map<String, Object> result = Maps.newHashMap();
        result.put("status", "success");
        result.put("data", data);
        result.put("availableUsers", availableUsers);
        result.put("availableLocations", availableLocations);

        try {
            OutputStream os = null;
            try {
                os = response.getOutputStream();
                response.setContentType("application/json");
                response.setHeader("Content-disposition",
                        String.format("attachment; filename=%s",
                                URLEncoder.encode("pan.pd", "UTF-8")));
                os.write(JsonUtils.pojoToJson(result).getBytes());
                os.flush();
            } catch (final Exception e) {
                InventoryDutyController.log.error("下载离线盘点文件失败", e);
            } finally {
                try {
                    os.close();
                } catch (final IOException e) {
                    InventoryDutyController.log.error("下载离线盘点文件失败", e);
                }
            }
        } catch (final Exception e) {
            InventoryDutyController.log.error("", e);
        }
    }

    @ApiOperation("导入离线盘点结果")
    @PostMapping("/upload/me")
    public ResultDTO<?> uploadMe(@RequestParam("file") final MultipartFile file) {
        final String msg = this.inventoryDutyService.uploadPd(file);
        if (!StringUtils.isEmpty(msg)) {
            return ResultDTO.failure(msg);
        }
        return ResultDTO.success(msg);
    }

    @ApiOperation("创建盘点任务")
    @PostMapping
    public ResultDTO<?> create(@RequestBody final InventoryDutyDTO dto) {
        this.inventoryDutyService.create(dto);
        return ResultDTO.success();
    }

    @ApiOperation("盘点任务详情")
    @GetMapping("/{id}")
    public ResultDTO<InventoryDutyDTO> details(@PathVariable final Long id) {
        final InventoryDutyDTO dto = this.inventoryDutyService.details(id);
        return ResultDTO.success(dto);
    }

    @ApiOperation("删除盘点任务")
    @DeleteMapping("/{id}")
    public ResultDTO<Void> delete(@PathVariable final Long id) {
        this.inventoryDutyService.delete(id);
        return ResultDTO.success();
    }

    @ApiOperation("修改盘点任务")
    @PutMapping("/{id}")
    public ResultDTO<InventoryDutyDTO> update(@PathVariable final Long id,
            @RequestBody final InventoryDutyDTO dto) {
        final InventoryDutyDTO result = this.inventoryDutyService.update(id, dto);
        return ResultDTO.success(result);
    }

    @ApiOperation("确认任务状态")
    @PutMapping("/enable/{id}/status/{status}")
    public ResultDTO<Void> enable(@PathVariable final Long id, @PathVariable final String status) {
        this.inventoryDutyService.enable(id, status);
        return ResultDTO.success();
    }

    @ApiOperation("导出任务详情")
    @GetMapping(value = "/export/{id}")
    public void download(@PathVariable final Long id, final HttpServletResponse response) {

        final Workbook workbook = this.inventoryDutyService.download(id);
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition",
                    String.format("attachment; filename=%s",
                            URLEncoder.encode("任务详情" + LocalDateTime.now() + ".xlsx", "UTF-8")));
            workbook.write(out);
            out.flush();
        } catch (final Exception e) {
            InventoryDutyController.log.error("任务详情导出失败", e);
        } finally {
            try {
                out.close();
            } catch (final IOException e) {
                InventoryDutyController.log.error("任务详情导出关闭流失败", e);
            }
        }
    }

    @ApiOperation("导入盘点任务表")
    @PostMapping("/import/{id}")
    public ResultDTO<?> upload(@RequestParam("file") final MultipartFile file, @PathVariable final Long id) {
        final String msg = this.inventoryDutyService.upload(file, id);
        if (!StringUtils.isEmpty(msg)) {
            return ResultDTO.failure(msg);
        }
        return ResultDTO.success(msg);
    }

    @ApiOperation("盘点任务执行历史")
    @GetMapping("/{id}/histories")
    public ResultListDTO<InventoryDutyHistoryDTO> history(@PathVariable final Long id) {
        final InventoryDutyDTO dto = this.inventoryDutyService.details(id);
        final List<InventoryDutyHistoryDTO> historyList = this.inventoryDutyHistoryService.findByDuty(dto.getCode());
        return ResultListDTO.success(historyList);
    }

    @ApiOperation("驳回盘点任务")
    @PutMapping("/{id}/reject")
    public ResultDTO<?> reject(@PathVariable final Long id, @RequestBody Map<String, Object> params) {
        final String reason = params.containsKey("reason") ? (String) params.get("reason") : "";
        this.inventoryDutyService.reject(id, reason);
        return ResultDTO.success();
    }

    private AuthOrgUserDTO convert(AuthOganization org) {
        final AuthOrgUserDTO dto = new AuthOrgUserDTO();
        dto.setCode(org.getCode());
        dto.setName(org.getName());
        return dto;
    }

    private Map<String, String> convert(AuthUserDTO user) {
        final Map<String, String> map = Maps.newHashMap();
        map.put("username", user.getUsername());
        map.put("name", user.getName());
        return map;
    }

    private void flatLocTree(List<Map<String, String>> results, List<TreeBean> children) {
        for (final TreeBean tree : children) {
            final Map<String, String> map = Maps.newHashMap();
            map.put("code", tree.getCode());
            map.put("name", tree.getTitle());

            results.add(map);
            this.flatLocTree(results, tree.getChildren());
        }
    }
}
